package com.score.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.score.handle.CustomAuthenticationEntryPoint;
import com.score.pojo.ResponseEntry;
import com.score.pojo.TRole;
import com.score.pojo.TUser;
import com.score.service.impl.UserDetailServiceImpl;
import com.score.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.session.InvalidSessionStrategy;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.PrintWriter;

@EnableWebSecurity
@EnableGlobalAuthentication
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserServiceImpl userService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/stuInfo").hasAnyRole("student")
//                .antMatchers("/socketio/**").permitAll()
                .antMatchers("/gmuscore/image/**").permitAll()
                .anyRequest().authenticated();
        http.formLogin()
                .loginProcessingUrl("/login/login").permitAll()
                .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest,
                                                        HttpServletResponse httpServletResponse,
                                                        Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
                        String username = userDetails.getUsername();
                        TUser user = userService.findByName(username);
                        TRole role = userService.getAuthority(user.getRoleId());
                        out.write("{\"code\":\"200\"," +
                                "\"message\":\"登录成功，欢迎您：" + username + "\"," +
                                "\"data\":{" +
                                "\"id\":\"" + user.getId() + "\"," +
                                "\"username\":\"" + user.getUsername() + "\"," +
                                "\"role\":\"" + role.getRole() +
                                "\"}}");
                        out.flush();
                        out.close();
                    }
                })
                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
                                                        HttpServletResponse httpServletResponse,
                                                        AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(new ResponseEntry(404, e.getMessage(), "用户名或密码错误，请重新登录")));
                        out.flush();
                        out.close();
                    }
                });
        //退出管理
        http.logout()
                .logoutUrl("/logout").permitAll()
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest,
                                                HttpServletResponse httpServletResponse,
                                                Authentication authentication) throws IOException, ServletException {
                        UserDetails principal = (UserDetails) authentication.getPrincipal();
//                        redisTemplate.delete("user::userAuth_"+principal.getUsername());
//                        redisTemplate.delete("user::user_" + principal.getUsername());
                        TUser user = userService.findByName(principal.getUsername());
                        httpServletResponse.setContentType("application/json;charset=UTF-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(new ResponseEntry().ok("用户退出:"+user.getUsername(),null)));
                        out.flush();
                        out.close();
                    }
                })
                .clearAuthentication(true)
                .invalidateHttpSession(true);
        //记住我功能
        http.rememberMe()
                .tokenValiditySeconds(24*60*60)
                .tokenRepository(tokenRepository());
        //会话管理
        http.sessionManagement()
                //配置session 失效策略
                .invalidSessionStrategy(new InvalidSessionStrategy() {
                    @Override
                    public void onInvalidSessionDetected(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException {
                        String id = httpServletRequest.getSession().getId();
                        if (id.equals("")){
                            httpServletResponse.setContentType("application/json;charset=UTF-8");
                            PrintWriter out = httpServletResponse.getWriter();
                            out.write(new ObjectMapper().writeValueAsString(new ResponseEntry(302, null, "session无效，请重新登录")));
                            out.flush();
                            out.close();
                        }
                    }
                });
                //最大会话数为1
//                .maximumSessions(10)
                //阻止新会话登录，而不是踢掉旧的会话，默认为false
//                .maxSessionsPreventsLogin(true);
        http.exceptionHandling()
                .authenticationEntryPoint(new CustomAuthenticationEntryPoint());
        http.csrf().disable().cors();

    }

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        auth.userDetailsService(userDetailService).passwordEncoder(encoder);
    }

    @Autowired
    private DataSource dataSource;

    public JdbcTokenRepositoryImpl tokenRepository() {
        JdbcTokenRepositoryImpl jr = new JdbcTokenRepositoryImpl();
        jr.setDataSource(dataSource);
        return jr;
    }

}